package com.think.cloud.thinkshop.mall.service.aftersales.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.think.cloud.thinkshop.mall.controller.admin.aftersales.vo.*;
import com.think.cloud.thinkshop.mall.controller.admin.index.dto.StatisticalTrendViewDTO;
import com.think.cloud.thinkshop.mall.controller.admin.message.dto.MessageTemplateReplaceDTO;
import com.think.cloud.thinkshop.mall.controller.app.payment.dto.RefundDTO;
import com.think.cloud.thinkshop.mall.convert.aftersales.AfterSalesConvert;
import com.think.cloud.thinkshop.mall.domain.aftersales.AfterSales;
import com.think.cloud.thinkshop.mall.domain.aftersales.AfterSalesLog;
import com.think.cloud.thinkshop.mall.domain.memberuser.MemberUser;
import com.think.cloud.thinkshop.mall.domain.order.Order;
import com.think.cloud.thinkshop.mall.domain.order.OrderLog;
import com.think.cloud.thinkshop.mall.domain.websitesetting.WebsiteSetting;
import com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesDelEnum;
import com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesOperateTypeEnum;
import com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesStatusEnum;
import com.think.cloud.thinkshop.mall.enums.common.CommonWhetherEnum;
import com.think.cloud.thinkshop.mall.enums.integral.IntegralBillTypeEnum;
import com.think.cloud.thinkshop.mall.enums.message.MessageTemplateEnum;
import com.think.cloud.thinkshop.mall.enums.order.OrderDetailStateEnum;
import com.think.cloud.thinkshop.mall.enums.order.OrderOperateTypeEnum;
import com.think.cloud.thinkshop.mall.enums.order.OrderOperateUserTypeEnum;
import com.think.cloud.thinkshop.mall.enums.order.OrderStatusEnum;
import com.think.cloud.thinkshop.mall.mapper.aftersales.AfterSalesMapper;
import com.think.cloud.thinkshop.mall.mapper.order.OrderMapper;
import com.think.cloud.thinkshop.mall.service.aftersales.IAfterSalesLogService;
import com.think.cloud.thinkshop.mall.service.aftersales.IAfterSalesService;
import com.think.cloud.thinkshop.mall.service.integral.IIntegralDetailService;
import com.think.cloud.thinkshop.mall.service.memberuser.IMemberUserService;
import com.think.cloud.thinkshop.mall.service.message.IMessageTemplateService;
import com.think.cloud.thinkshop.mall.service.order.AppOrderLogService;
import com.think.cloud.thinkshop.mall.service.order.IOrderDetailService;
import com.think.cloud.thinkshop.mall.service.payment.PaymentService;
import com.think.cloud.thinkshop.mall.service.websitesetting.IWebsiteSettingService;
import com.think.common.core.exception.ServiceException;
import com.think.common.core.exception.util.ServiceExceptionUtil;
import com.think.common.core.utils.PageUtils;
import com.think.common.core.web.page.TableDataInfo;
import com.think.common.security.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesOperateTypeEnum.*;
import static com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesStatusEnum.*;
import static com.think.cloud.thinkshop.mall.enums.aftersales.AfterSalesTypeEnum.REFUND_ONLY;
import static com.think.common.core.exception.enums.ErrorCode.AFTER_SALES_NOT_EXIST_ERROR;
import static com.think.common.core.exception.enums.ErrorCode.SALES_NOT_USER_DEL_ERROR;

/**
 * 售后记录Service业务层处理
 *
 * @author zkthink
 * @date 2024-06-12
 */
@Service
public class AfterSalesServiceImpl implements IAfterSalesService {

    @Autowired
    private AfterSalesMapper afterSalesMapper;

    @Autowired
    private IOrderDetailService orderDetailService;

    @Autowired
    private IAfterSalesLogService afterSalesLogService;

    @Autowired
    private IWebsiteSettingService websiteSettingService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private IMemberUserService memberUserService;

    @Autowired
    private IMessageTemplateService messageTemplateService;

    @Autowired
    private IIntegralDetailService integralDetailService;

    @Autowired
    private AppOrderLogService orderLogService;

    /**
     * 查询售后记录
     *
     * @param id 售后记录主键
     * @return 售后记录
     */
    @Override
    public AfterSalesInfoRespVO selectAfterSalesById(Long id) {
        AfterSalesInfoRespVO result = AfterSalesConvert.INSTANCE.convert1(getAfterSales(id));
        // 查询订单信息
        Order order = this.findOrderById(result.getOrderId());
        result.setOrderCode(order.getOrderCode());
        // 查询订单明细
        List<AfterSalesOrderDetailRespVO> afterSalesDetails = this.findOrderDetailListByAfterSalesIds(Arrays.asList(id));
        result.setDetails(afterSalesDetails);
        // 查询操作日志
        List<AfterSalesLogRespVO> afterSalesLogs = afterSalesLogService.selectAfterSalesLogListByAfterSalesId(id);
        result.setLogs(afterSalesLogs);
        result.setOrderUser(getUserInfo(order.getUserId()).getEmail());
        return result;
    }

    private Order findOrderById(Long id) {
        return orderMapper.selectById(id);
    }

    private MemberUser getUserInfo(Long id) {
       return memberUserService.selectMemberUserById(id);
    }

    /**
     * 查询售后记录列表
     *
     * @param vo
     * @return 售后记录
     */
    @Override
    public TableDataInfo selectAfterSalesList(AfterSalesPageReqVO vo) {
        List<AfterSalesPageRespVO> afterSalesList = afterSalesMapper.selectAppAfterSaleList(vo);
        if (CollectionUtil.isNotEmpty(afterSalesList)) {
            List<Long> afterSalesIds = afterSalesList.stream().map(AfterSalesPageRespVO::getId).collect(Collectors.toList());
            // 查询订单明细
            List<AfterSalesOrderDetailRespVO> afterSalesDetails = this.findOrderDetailListByAfterSalesIds(afterSalesIds);
            Map<Long, List<AfterSalesOrderDetailRespVO>> orderDetailMap =
                    afterSalesDetails.stream().collect(Collectors.groupingBy(AfterSalesOrderDetailRespVO::getAfterSalesId));
            afterSalesList.forEach(res -> res.setDetails(orderDetailMap.get(res.getId())));
        }
        return new TableDataInfo(afterSalesList, PageUtils.getTotal(afterSalesList));
    }

    // 通过售后订单id查询主订单详情
    private List<AfterSalesOrderDetailRespVO> findOrderDetailListByAfterSalesIds(List<Long> afterSalesIds) {
        return orderDetailService.selectOrderDetailListByAfterSalesIds(afterSalesIds);
    }

    private AfterSales getAfterSales(Long id) {
        AfterSales afterSales = afterSalesMapper.selectById(id);
        if (Objects.isNull(afterSales)) throw ServiceExceptionUtil.exception(AFTER_SALES_NOT_EXIST_ERROR);
        return afterSales;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void audit(AfterSalesAuditReqVO vo) {
        Long id = vo.getId();
        //操作用户的id ，用来记录日志
        Long operateUserId = vo.getUserId();
        String remark = vo.getRemark();

        AfterSales afterSales = getAfterSales(id);
        Long orderId = afterSales.getOrderId();
        Integer state = afterSales.getState();
        //售后单所属的用户id
        Long afterSalesUserId = afterSales.getUserId();
        MemberUser memberUser = this.getUserInfo(afterSalesUserId);
        //拒绝
        if (CommonWhetherEnum.NO.getValue().equals(vo.getIsAgree())) {
            if (remark == null || remark.isEmpty()) {
                throw new ServiceException("拒绝审核时拒绝原因不能为空！");
            }
            commonUpdate(id, BUSINESS_REFUSE, operateUserId, remark);
            Order order = findOrderById(orderId);
            //售后被拒绝，发送通知
            MessageTemplateReplaceDTO build = MessageTemplateReplaceDTO.builder()
                    .email(memberUser.getEmail())
                    .orderCode(order.getOrderCode())
                    .rejectReason(remark)
                    .orderId(orderId)
                    .build();
            messageTemplateService.sendMessageText(MessageTemplateEnum.TEMPLATE_9, build, afterSalesUserId);
            return;
        }
        Integer serviceType = afterSales.getServiceType();
        // 同意售后
        if (AWAITING_AUDIT.getValue().equals(state) && !REFUND_ONLY.getValue().equals(serviceType)) {
            commonUpdate(id, AWAITING_SHIPMENT, operateUserId, remark);
            //同意退款
        } else if (AWAITING_RECEIPT.getValue().equals(state) || REFUND_ONLY.getValue().equals(serviceType)) {
            commonUpdate(id, AGREE_REFUND, operateUserId, remark);
            refund(afterSales);
        } else {
            throw ServiceExceptionUtil.exception(AFTER_SALES_NOT_EXIST_ERROR);
        }
    }

    @Override
    public int delete(Long id) {
        AfterSales afterSales = getAfterSales(id);
        Integer userDel = afterSales.getUserDel();
        if (userDel.equals(AfterSalesDelEnum.NO.getValue())) {
            throw ServiceExceptionUtil.exception(SALES_NOT_USER_DEL_ERROR);
        }
        return afterSalesMapper.deleteById(id);

    }

    /**
     * 通用更新
     *
     * @param id        售后id
     * @param stateEnum 售后状态枚举
     * @param userId    登录用户id
     */
    private void commonUpdate(Long id, AfterSalesStatusEnum stateEnum, Long userId, String remark) {
        AfterSales afterSales = AfterSales.builder().id(id).state(stateEnum.getValue()).remark(remark).build();
        AfterSalesOperateTypeEnum operateType = null;
        switch (stateEnum) {
            case BUSINESS_REFUSE:
                operateType = APPROVAL_FAILED;
                // 修改订单详情状态
                this.updateOrderDetailByAfterSalesId(id, OrderDetailStateEnum.NORMAL);
                break;
            case AWAITING_SHIPMENT:
                operateType = APPROVAL_SUCCESSFUL;
                addAddress(afterSales); //存入退货地址信息
                break;
            case AGREE_REFUND:
                operateType = MERCHANT_AGREED_TO_REFUND;
                break;
            case COMPLETED:
                operateType = REFUND_SUCCESSFUL;
                // 修改订单详情状态
                this.updateOrderDetailByAfterSalesId(id, OrderDetailStateEnum.COMPLETED_AFTER_SALES);
        }
        // 更新售后单状态
        afterSalesMapper.updateById(afterSales);
        AfterSalesLog afterSalesLog = AfterSalesLog.builder()
                .afterSalesId(id)
                .userType(OrderOperateUserTypeEnum.MERCHANT.getValue())
                .userId(userId)
                .operateType(operateType.getValue())
                .build();
        afterSalesLog.setCreateBy(SecurityUtils.getUsername());
        // 存入操作记录
        afterSalesLogService.insertSalesLog(afterSalesLog);
    }

    //通过售后订单idx修改订单详情状态
    private void updateOrderDetailByAfterSalesId(Long afterSalesId, OrderDetailStateEnum stateEnum) {
        orderDetailService.updateOrderDetailByAfterSalesId(afterSalesId, stateEnum.getValue());
    }

    private void addAddress(AfterSales afterSales) {
        WebsiteSetting websiteSetting = this.websiteSettingCache();
        afterSales.setConsignee(websiteSetting.getAddressUsername());
        afterSales.setPhoneNumber(websiteSetting.getAddressPhoneNumber());
        afterSales.setAddress(websiteSetting.getAddressDetails());
        afterSales.setCountry(websiteSetting.getAddressNation());
        afterSales.setPostCode(websiteSetting.getAddressPostcode());
    }

    // 获取配置
    private WebsiteSetting websiteSettingCache() {
        return websiteSettingService.getCache();
    }

    /**
     * 退款操作
     *
     * @param afterSales
     */
    private void refund(AfterSales afterSales) {
        Long orderId = afterSales.getOrderId();
        Order order = this.findOrderById(orderId);

        RefundDTO dto = new RefundDTO();
        dto.setOrderCode(order.getOrderCode());
        //退款金额
        BigDecimal refundAmount = afterSales.getRefundAmount();
        dto.setTotal(refundAmount);

        WebsiteSetting websiteSetting = this.websiteSettingCache();
        dto.setCurrency(websiteSetting.getCurrencyCode());
        dto.setPaymentIntent(order.getPaymentIntentId());
        dto.setLatestCharge(order.getLatestCharge());

        Long userId = afterSales.getUserId();
        // 校验退款是否成功
        if (paymentService.createRefund(dto, order.getPayType())) {
            commonUpdate(afterSales.getId(), COMPLETED, userId, null);
            // 订单全部售后完成
            if (orderDetailService.determineAfterSalesCompleted(orderId)) {
                orderMapper.updateById(Order.builder()
                        .id(orderId)
                        .status(OrderStatusEnum.COMPLETED.getValue())
                        .build()
                );
                orderLogService.insertOrderLog(OrderLog.builder()
                        .orderId(orderId)
                        .userId(userId)
                        .userType(OrderOperateUserTypeEnum.USER.getValue())
                        .operateType(OrderOperateTypeEnum.SHIP_BY_MERCHANT.getValue())
                        .build()
                );
                orderLogService.insertOrderLog(OrderLog.builder()
                        .orderId(orderId)
                        .userId(userId)
                        .userType(OrderOperateUserTypeEnum.USER.getValue())
                        .operateType(OrderOperateTypeEnum.CONFIRM_RECEIPT.getValue())
                        .build()
                );
            }
            //更新用户退款数据
            memberUserService.updateUserRefundData(userId, refundAmount);
            Integer useIntegral = order.getUseIntegral();
            // 售后退回积分
            if (useIntegral!=null && useIntegral>0){
                integralDetailService.insertIntegralDetail(userId, useIntegral, IntegralBillTypeEnum.SALE_AFTER);
            }
            // 退款成功通知
            MessageTemplateReplaceDTO build = MessageTemplateReplaceDTO.builder()
                    .orderCode(order.getOrderCode())
                    .currencyUnit(websiteSetting.getCurrencySymbol())
                    .payPrice(refundAmount.toString())
                    .orderId(orderId)
                    .build();
            messageTemplateService.sendMessageText(MessageTemplateEnum.TEMPLATE_8, build, userId);
        }
    }

    /**
     * 统计的查询条件
     */
    private LambdaQueryWrapper<Order> statisticCondition(String startTime, String endTime) {
        return Wrappers.<Order>lambdaQuery()
                .ge(ObjectUtil.isNotNull(startTime), Order::getCreateTime, startTime)
                .le(ObjectUtil.isNotNull(startTime), Order::getCreateTime, endTime)
                ;
    }

    @Override
    public List<StatisticalTrendViewDTO> saledOrderCountTrend(String startTime, String endTime) {
        return afterSalesMapper.afterSalesCountTrend(statisticCondition(startTime, endTime));
    }

    @Override
    public List<StatisticalTrendViewDTO> saledOrderAmountTrend(String startTime, String endTime) {
        return afterSalesMapper.afterSalesAmountTrend(statisticCondition(startTime, endTime));
    }
}
